﻿using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;

using BizElements.Core.ProviderComponents;

namespace BizElements.Core
{
    #region Documentation.
    /// <summary>
    /// Defines methods implemented by all database entity data-access classes.
    /// </summary>
    /// <remarks>Entity DAO requires an instance of IEntity (see <see cref="IEntityDAO.Entity"/>) to work. 
    /// This is the target entity to which results of data retrieval are stored in (eg. CRUD methods). It also serves 
    /// as a source of data for other methods (eg. <see cref="Find(int)"/>).
    /// <p>Main features:
    /// <list type="bullet">
    /// <item>CRUD methods. Create, retrieve, update and delete methods that manipulate a single row in the 
    /// database using primary key logic. All CRUD methods have a suffix <b>One.</b></item>
    /// <item>Retrieval of parent entities using foreign keys mapped in IDbTable meta classes.</item>
    /// <item>Retrieval of child entities using one-to-many and many-to-many relations.</item>
    /// <item>Batch manipulation and retrieval of multiple rows.</item>
    /// <item>Aggregate functions.</item>
    /// <item>Sorting of retrieved rows on database or in application.</item>
    /// <item>Connection and transaction sharing with other data-tier objects.</item>
    /// <item>Hierarchical queries and updates - methods with a suffix <b>Tree</b>.</item>
    /// </list></p></remarks>
    /// <seealso cref="EntityDAO"/>
    /// <seealso cref="EntityDaoExtensions"/>
    #endregion
    public interface IEntityDAO : IDataAccessObject
    {
        #region Properties.

        /// <summary>
        /// Gets or sets entity with which DAO works.
        /// </summary>
        /// <remarks>Depending on operation DAO may only read entity, but it may also change it.
        /// CRUD operations both read and update entity.</remarks>
        IEntity Entity { get; set; }

        /// <summary>Gets table where the entities managed by current instance are stored. Must be equal to table referenced by entity in <see cref="Entity"/> property.</summary>
        IDbTable Table { get; }

        #endregion

        #region Methods.

        /// <summary>
        /// Sets the sorter used by the data retrieval methods.
        /// </summary>
        /// <param name="sorter">Sort clause. May be <b>null</b>.</param>
        void SetSorter(OrderByClause sorter);

        /// <summary>
        /// Sets the sort mode for data retrieveal methods. This is just a hint. Data retrieval methods may ignore this.
        /// </summary>
        /// <param name="sortOnDatabase">Specifies whether sorting will take place on database or in application after data has been fetched.</param>
        void SetSortMode(bool sortOnDatabase);

        #endregion

        // Entity methods.

        #region Entity data access methods. Affect a single row. Suffix "One".

        /// <summary>
        /// Deletes one existing row in the database based on the Primary Key.
        /// </summary>
        /// <returns>Number of rows affected.</returns>
        int DeleteOne();

        /// <summary>
        /// Inserts one new row into the database.
        /// </summary>
        /// <returns>Autoidentity value for the inserted row. <b>null</b> if the table doesn't contain an 
        /// autoidentity field or the DBMS specific code cannot be generated.</returns>
        object InsertOne();

        /// <summary>
        /// Selects one existing entity from the database based on the Primary Key and populates entity with the retrieved data.
        /// </summary>		
        /// <remarks>True if select succeeded; false otherwise.</remarks>
        bool SelectOne();

        /// <summary>
        /// Updates one existing row in the database.
        /// </summary>
        /// <returns>Number of rows affected.</returns>
        int UpdateOne();

        /// <summary>
        /// Persists entity. Operation (insert, update, nothing) is chosen based on the current <see cref="EntityState"/>.
        /// </summary>
        /// <returns>True if entity was persisted; false otherwise.</returns>
        bool Save();

        #endregion

        #region Fetch parents and select one with parents.

        /// <summary>Selects an existing entity and initializes the specified parent entities.</summary>
        /// <param name="parentsToFetch">Relations (foreign keys) to parents which are to be fetched. Child table 
        /// of the given FK must be the current entity's table;  otherwise an exception is generated.</param>
        /// <returns>True if select succeeded; false otherwise.</returns>
        bool SelectOne(params DbRelation[] parentsToFetch);

        /// <summary>Selects an existing and partially initializes parent entities.</summary>
        /// <param name="parentsToFetch">Relations (foreign keys) to parents which are to be fetched. Child table 
        /// of the given FK must be the current entity's table;  otherwise an exception is generated.</param>
        /// <param name="parentColumnsToFetch">Fields that belong to parent tables. Only specified parent fields will be fetched and initialized.</param>
        /// <returns>True if select succeeded; false otherwise.</returns>
        bool SelectOne(IEnumerable<DbRelation> parentsToFetch, IEnumerable<IDbColumn> parentColumnsToFetch);

        /// <summary>
        /// Fetches a parent entity defined by the foreign key from the data source and stores it into current entity.
        /// </summary>
        /// <param name="foreignKey">FK. Child table of the given FK must be the current entity's table; 
        /// otherwise an exception is generated.</param>
        /// <returns>Parent entity. Parent entity. <b>Null</b> if the FK fields haven't been set or if the parent entity with the given key values doesn't exist.</returns>
        IEntity FetchParent(DbRelation foreignKey);

        /// <summary>
        /// Fetches parent entities defined by the given relations from the data source and stores them into current entity.
        /// </summary>
        /// <param name="parentsToFetch">Relations (foreign keys) to parents which are to be fetched. Child table 
        /// of the given FK must be the current entity's table; otherwise an exception is generated.</param>
        /// <returns>Parent entities. Some may be <b>null</b> if the required FK fields haven't been set or if the entities 
        /// with the given key values don't exist.</returns>
        IEntity[] FetchParents(params DbRelation[] parentsToFetch);

        #endregion

        #region 1:N children.

        #region Documentation.
        /// <summary>
        /// Fetches child entities that reference the current entity.
        /// </summary>
        /// <param name="destination">A collection to fill with entities built from data. Will contain entities from the child table whose foreign key matches this entity's primary key.</param>
        /// <param name="relation">Relation between the current entity's table and another (child) table. 
        /// Parent table of the given relation must be this entity's table; otherwise an exception is generated.</param>
        /// <param name="childRowsFilter">Filters which child table records are to be returned. Typically used to filter out inactive records.</param>
        /// <param name="orderBy">Specifies the order in which the entities are added to output collection.</param>
        /// <remarks>The method uses a <see cref="SearchCondition"/> to select only the child rows where the specified criteria is matched.
        /// Very often a database is designed so that the child entities are not deleted from the database but are 
        /// marked as deleted instead. This method may be used when only child rows with a specific status value 
        /// (eg. STATUS = 1) are to be fetched.</remarks>
        #endregion
        void FetchChildren(IList destination, DbRelation relation, SearchCondition childRowsFilter, OrderByClause orderBy);

        #region Documentation.
        /// <summary>
        /// Fetches child entities that reference the current entity.
        /// </summary>
        /// <param name="relation">Relation between the current entity's table and another (child) table. 
        /// Parent table of the given relation must be this entity's table; otherwise an exception is generated.</param>
        /// <param name="childRowsFilter">Filters which child table records are to be returned. Typically used to filter out inactive records.</param>
        /// <param name="orderBy">Specifies the order in which the entities are added to output collection.</param>
        /// <returns>Rows from the child table that reference the current entity and match the given criteria.</returns>
        /// <remarks>The method uses a <see cref="SearchCondition"/> to select only the child rows where the specified criteria is matched.
        /// Very often a database is designed so that the child entities are not deleted from the database but are 
        /// marked as deleted instead. This method may be used when only child rows with a specific status value 
        /// (eg. STATUS = 1) are to be fetched.</remarks>
        #endregion
        DataTable FetchChildren(DbRelation relation, SearchCondition childRowsFilter, OrderByClause orderBy);

        #endregion

        #region M:N children.

        #region Documentation.
        /// <summary>
        /// Fetches child entities that reference the current entity.
        /// </summary>
        /// <param name="destination">A collection to fill with entities built from data. Will contain entities from the child table whose foreign key matches this entity's primary key.</param>
        /// <param name="mnRelation">Many-to-many relation. Current entity's table acts as a parent table,
        /// the other primary table in the relation acts as a child. May be recursive.</param>
        /// <param name="childRowsFilter">Filters which child table records are to be returned. Typically used to filter out inactive records.</param>
        /// <param name="orderBy">Specifies the order in which the entities are added to output collection.</param>
        /// <remarks><p>The method uses a <see cref="SearchCondition"/> that compares the specified column to 
        /// the given value. Only the child rows that match the specified criteria are selected. 
        /// Very often database is designed so that the child entities are not deleted from the database but are 
        /// marked as deleted instead. This method may be used when only child rows with a specific status value 
        /// (eg. STATUS = 1) are to be fetched. In addition, a SearchCondition may be created which filters out rows 
        /// from the junction table. See <see cref="ManyToManyRelation.JunctionRowsFilter"/> for more information.</p>
        /// <p>When a single database table is used as both the first and the second primary table of an M:N 
        /// relation then it must be explicitly specified which one is used as a parent and which one as a child table.</p></remarks>
        #endregion
        void FetchChildren(IList destination, ManyToManyRelation mnRelation, SearchCondition childRowsFilter, OrderByClause orderBy);

        #region Documentation.
        /// <summary>
        /// Fetches child entities that reference the current entity.
        /// </summary>
        /// <param name="destination">A collection to fill with entities built from data. Will contain entities from the child table whose foreign key matches this entity's primary key.</param>
        /// <param name="mnRelation">Many-to-many relation. Current entity's table acts as a parent table,
        /// the other primary table in the relation acts as a child. May be recursive.</param>
        /// <param name="parentSpecifier">Indicates which of the two primary tables in the M:N relation acts as a parent.</param>
        /// <param name="childRowsFilter">Filters which child table records are to be returned. Typically used to filter out inactive records.</param>
        /// <param name="orderBy">Specifies the order in which the entities are added to output collection.</param>
        /// <remarks><p>The method uses a <see cref="SearchCondition"/> that compares the specified column to 
        /// the given value. Only the child rows that match the specified criteria are selected. 
        /// Very often database is designed so that the child entities are not deleted from the database but are 
        /// marked as deleted instead. This method may be used when only child rows with a specific status value 
        /// (eg. STATUS = 1) are to be fetched. In addition, a SearchCondition may be created which filters out rows 
        /// from the junction table. See <see cref="ManyToManyRelation.JunctionRowsFilter"/> for more information.</p>
        /// <p>When a single database table is used as both the first and the second primary table of an M:N 
        /// relation then it must be explicitly specified which one is used as a parent and which one as a child table.</p></remarks>
        #endregion
        void FetchChildren(IList destination, ManyToManyRelation mnRelation, PrimaryTableIndex parentSpecifier, SearchCondition childRowsFilter, OrderByClause orderBy);

        #region Documentation.
        /// <summary>
        /// Fetches child entities that reference the current entity.
        /// </summary>
        /// <param name="mnRelation">Many-to-many relation. Current entity's table acts as a parent table,
        /// the other primary table in the relation acts as a child. May be recursive.</param>
        /// <param name="childRowsFilter">Filters which child table records are to be returned. Typically used to filter out inactive records.</param>
        /// <param name="orderBy">Specifies the order in which the entities are added to output collection.</param>
        /// <remarks><p>The method uses a <see cref="SearchCondition"/> that compares the specified column to 
        /// the given value. Only the child rows that match the specified criteria are selected. 
        /// Very often database is designed so that the child entities are not deleted from the database but are 
        /// marked as deleted instead. This method may be used when only child rows with a specific status value 
        /// (eg. STATUS = 1) are to be fetched. In addition, a SearchCondition may be created which filters out rows 
        /// from the junction table. See <see cref="ManyToManyRelation.JunctionRowsFilter"/> for more information.</p>
        /// <p>When a single database table is used as both the first and the second primary table of an M:N 
        /// relation then it must be explicitly specified which one is used as a parent and which one as a child table.</p></remarks>
        #endregion
        DataTable FetchChildren(ManyToManyRelation mnRelation, SearchCondition childRowsFilter, OrderByClause orderBy);

        #region Documentation.
        /// <summary>
        /// Fetches child entities that reference the current entity.
        /// </summary>
        /// <param name="mnRelation">Many-to-many relation. Current entity's table acts as a parent table,
        /// the other primary table in the relation acts as a child. May be recursive.</param>
        /// <param name="parentSpecifier">Indicates which of the two primary tables in the M:N relation acts as a parent.</param>
        /// <param name="childRowsFilter">Filters which child table records are to be returned. Typically used to filter out inactive records.</param>
        /// <param name="orderBy">Specifies the order in which the entities are added to output collection.</param>
        /// <remarks><p>The method uses a <see cref="SearchCondition"/> that compares the specified column to 
        /// the given value. Only the child rows that match the specified criteria are selected. 
        /// Very often database is designed so that the child entities are not deleted from the database but are 
        /// marked as deleted instead. This method may be used when only child rows with a specific status value 
        /// (eg. STATUS = 1) are to be fetched. In addition, a SearchCondition may be created which filters out rows 
        /// from the junction table. See <see cref="ManyToManyRelation.JunctionRowsFilter"/> for more information.</p>
        /// <p>When a single database table is used as both the first and the second primary table of an M:N 
        /// relation then it must be explicitly specified which one is used as a parent and which one as a child table.</p></remarks>
        #endregion
        DataTable FetchChildren(ManyToManyRelation mnRelation, PrimaryTableIndex parentSpecifier, SearchCondition childRowsFilter, OrderByClause orderBy);

        #endregion

        #region Hierarchical queries and updates.

        /// <summary>
        /// Selects rows in the hierarchy under the current entity.
        /// </summary>
        /// <param name="recursiveRelation">Recursive relation which defines a hierarchy.</param>
        /// <param name="leafFilter">The search condition which restricts the rows returned. Often a criteria which filters out deactivated records.</param>
        /// <param name="beginAtLevel">Zero-based index of the first level to fetch. Zero indicates that fetching starts at current entity,
        /// one indicates that fetching starts at the level directly beneath it etc.</param>
        /// <param name="endAtLevel">Zero-based index of the last level to fetch. Zero indicates that fetching ends at current entity,
        /// one indicates that fetching ends at the level directly beneath it etc. <see cref="System.Int32.MaxValue"/> indicates that operation ends at leaf nodes.</param>
        /// <returns>Rows in the hierarchy under the current entity.</returns>
        DataTable SelectTree(DbRelation recursiveRelation, SearchCondition leafFilter, int beginAtLevel, int endAtLevel);

        /// <summary>
        /// Counts the number of levels in the hieararchy starting with the current entity.
        /// </summary>
        /// <param name="recursiveRelation">Recursive relation which defines a hierarchy.</param>
        /// <returns>Sub-tree depth.</returns>
        int DetermineTreeDepth(DbRelation recursiveRelation);

        /// <summary>
        /// Updates rows in the hierarchy under the current entity.
        /// </summary>
        /// <param name="recursiveRelation">Recursive relation which defines a hierarchy.</param>
        /// <param name="setExpressions">The list of columns to be updated and expressions that compute/contain the new values.</param>
        /// <param name="leafFilter">The search condition which limits the number of rows that are updated. Often a criteria which filters out deactivated records.</param>
        /// <param name="beginAtLevel">Zero-based index of the first level to update. Zero indicates that updating starts at current entity,
        /// one indicates that updating starts at the level directly beneath it etc.</param>
        /// <param name="endAtLevel">Zero-based index of the last level to update. Zero indicates that updating ends at current entity,
        /// one indicates that updating ends at the level directly beneath it etc. <see cref="System.Int32.MaxValue"/> indicates that operation ends at leaf nodes.</param>
        /// <returns>Number of rows affected.</returns>
        int UpdateTree(DbRelation recursiveRelation, UpdateList setExpressions, SearchCondition leafFilter, int beginAtLevel, int endAtLevel);

        /// <summary>
        /// Counts rows in the hierarchy under the current entity.
        /// </summary>
        /// <param name="recursiveRelation">Recursive relation which defines a hierarchy.</param>
        /// <param name="leafFilter">The search condition which restricts the rows counted. Often a criteria which filters out deactivated records.</param>
        /// <param name="beginAtLevel">Zero-based index of the first level to process. Zero indicates that counting starts at current entity,
        /// one indicates that counting starts at the level directly beneath it etc.</param>
        /// <param name="endAtLevel">Zero-based index of the last level to process. Zero indicates that counting ends at current entity,
        /// one indicates that counting ends at the level directly beneath it etc. <see cref="System.Int32.MaxValue"/> indicates that operation ends at leaf nodes.</param>
        /// <returns>Total row count in the hierarchy.</returns>
        int CountTree(DbRelation recursiveRelation, SearchCondition leafFilter, int beginAtLevel, int endAtLevel);

        /// <summary>
        /// Retrieves the sum of the column values in the hierarchy under the current entity.
        /// </summary>
        /// <param name="column">Column. Must be a numeric column that belongs to the current entity's table.</param>
        /// <param name="recursiveRelation">Recursive relation which defines a hierarchy.</param>
        /// <param name="leafFilter">The search condition which restricts the rows processed. Often a criteria which filters out deactivated records.</param>
        /// <param name="beginAtLevel">Zero-based index of the first level to process. Zero indicates that summing starts at current entity,
        /// one indicates that summing starts at the level directly beneath it etc.</param>
        /// <param name="endAtLevel">Zero-based index of the last level to process. Zero indicates that summing ends at current entity,
        /// one indicates that summing ends at the level directly beneath it etc. <see cref="System.Int32.MaxValue"/> indicates that operation ends at leaf nodes.</param>
        /// <returns>Total sum of column values in the hierarchy or <see cref="DBNull.Value"/>.</returns>
        object SumTree(IDbColumn column, DbRelation recursiveRelation, SearchCondition leafFilter, int beginAtLevel, int endAtLevel);

        /// <summary>
        /// Retrieves the minimum column value in the hierarchy under the current entity.
        /// </summary>
        /// <param name="column">Column to compare. Must belong to the current entity's table.</param>
        /// <param name="recursiveRelation">Recursive relation which defines a hierarchy.</param>
        /// <param name="leafFilter">The search condition which restricts the rows processed. Often a criteria which filters out deactivated records.</param>
        /// <param name="beginAtLevel">Zero-based index of the first level to process. Zero indicates that comparison starts at current entity,
        /// one indicates that comparison starts at the level directly beneath it etc.</param>
        /// <param name="endAtLevel">Zero-based index of the last level to process. Zero indicates that comparison ends at current entity,
        /// one indicates that comparison ends at the level directly beneath it etc. <see cref="System.Int32.MaxValue"/> indicates that operation ends at leaf nodes.</param>
        /// <returns>Minimum value or <see cref="DBNull.Value"/>.</returns>
        object MinInTree(IDbColumn column, DbRelation recursiveRelation, SearchCondition leafFilter, int beginAtLevel, int endAtLevel);

        /// <summary>
        /// Retrieves the maximum column value in the hierarchy under the current entity.
        /// </summary>
        /// <param name="column">Column to compare. Must belong to the current entity's table.</param>
        /// <param name="recursiveRelation">Recursive relation which defines a hierarchy.</param>
        /// <param name="leafFilter">The search condition which restricts the rows processed. Often a criteria which filters out deactivated records.</param>
        /// <param name="beginAtLevel">Zero-based index of the first level to process. Zero indicates that comparison starts at current entity,
        /// one indicates that comparison starts at the level directly beneath it etc.</param>
        /// <param name="endAtLevel">Zero-based index of the last level to process. Zero indicates that comparison ends at current entity,
        /// one indicates that comparison ends at the level directly beneath it etc. <see cref="System.Int32.MaxValue"/> indicates that operation ends at leaf nodes.</param>
        /// <returns>Maximum value or <see cref="DBNull.Value"/>.</returns>
        object MaxInTree(IDbColumn column, DbRelation recursiveRelation, SearchCondition leafFilter, int beginAtLevel, int endAtLevel);

        #endregion     

        // Table data access methods. Affect multiple rows.

        #region Delete.

        /// <summary>Deletes all rows that match the filter criteria.</summary>
        /// <param name="filter">The search condition which limits the number of rows that are deleted.</param>
        /// <returns>Number of rows affected.</returns>
        int Delete(SearchCondition filter);   

        #endregion

        #region Update.

        /// <summary>
        /// Updates all rows that match the filter criteria.
        /// </summary>
        /// <param name="setExpressions">The list of columns to be updated and expressions that compute/contain the new values.</param>		
        /// <param name="filter">The search condition which limits the number of rows that are updated.</param>
        /// <returns>Number of rows affected.</returns>
        /// <remarks>Updates all rows in this table that match the specified filter with values/expressions in the given SET list.</remarks>
        int Update(UpdateList setExpressions, SearchCondition filter);

        #endregion

        #region Select.

        /// <summary>
        /// Selects all rows that match the filter criteria. Data is sorted if the sorter is set.
        /// </summary>
        /// <param name="destination">A collection to fill with entities built from data.</param>
        /// <param name="relations">Relations. May be <b>null</b> if the filter doesn't use other tables.</param>
        /// <param name="filter">The search condition which restricts the rows returned.</param>		
        /// <param name="maxNumberOfItemsToReturn">Maximum number of items that will be returned. 
        /// If set to zero or a negative value, all rows matching criteria will be returned.</param>
        void Select(IList destination, RelationBucket relations, SearchCondition filter, int maxNumberOfItemsToReturn);

        /// <summary>
        /// Selects all rows that match the filter criteria. Data is sorted if the sorter is set.
        /// </summary>
        /// <param name="relations">Relations. May be <b>null</b> if the filter doesn't use other tables.</param>
        /// <param name="filter">The search condition which restricts the rows returned.</param>		
        /// <param name="maxNumberOfItemsToReturn">Maximum number of items that will be returned. 
        /// If set to zero or a negative value, all rows matching criteria will be returned.</param>
        /// <returns>Data that matches the filter.</returns>
        DataTable Select(RelationBucket relations, SearchCondition filter, int maxNumberOfItemsToReturn);

        #endregion

        #region Find.

        /// <summary>
        /// Selects all rows that match an automatically created filter based on all properties that have been set.
        /// Predicates are combined by AND operators. Data is sorted if the sorter is set.
        /// </summary>
        /// <param name="destination">A collection to fill with entities built from data.</param>
        /// <param name="maxNumberOfItemsToReturn">Maximum number of items that will be returned. 
        /// If set to zero or a negative value, all rows matching the criteria will be returned.</param>
        void Find(IList destination, int maxNumberOfItemsToReturn);

        /// <summary>
        /// Selects all rows that match an automatically created filter based on all properties that have been set.
        /// Predicates are combined by AND operators. Data is sorted if the sorter is set.
        /// </summary>
        /// <param name="maxNumberOfItemsToReturn">Maximum number of items that will be returned. 
        /// If set to zero or a negative value, all rows matching the criteria will be returned.</param>
        /// <returns>Rows that match the automatically created filter.</returns>
        DataTable Find(int maxNumberOfItemsToReturn);

        /// <summary>
        /// Selects all rows that match an automatically created filter based on all properties that have been set. 
        /// Predicates are combined by OR operators. Data is sorted if the sorter is set.
        /// </summary>
        /// <param name="destination">A collection to fill with entities built from data.</param>
        /// <param name="maxNumberOfItemsToReturn">Maximum number of items that will be returned. 
        /// If set to zero or a negative value, all rows matching criteria will be returned.</param>
        void FindMatchingAnyCriteria(IList destination, int maxNumberOfItemsToReturn);

        /// <summary>
        /// Selects all rows that match an automatically created filter based on all properties that have been set. 
        /// Predicates are combined by OR operators. Data is sorted if the sorter is set.
        /// </summary>
        /// <param name="maxNumberOfItemsToReturn">Maximum number of items that will be returned. 
        /// If set to zero or a negative value, all rows matching criteria will be returned.</param>
        /// <returns>Rows that match the automatically created filter.</returns>		
        DataTable FindMatchingAnyCriteria(int maxNumberOfItemsToReturn);

        #endregion

        #region Aggregate functions.

        /// <summary>
        /// Counts all rows in the entity's parent table that match the filter criteria.
        /// </summary>
        /// <param name="relations">Relations. May be <b>null</b> if the filter doesn't use other tables.</param>
        /// <param name="filter">The search condition which restricts the rows counted.</param>
        /// <returns>Number of rows that match the filter.</returns>
        int Count(RelationBucket relations, SearchCondition filter);

        /// <summary>
        /// Retrieves the maximum value in the given column.
        /// </summary>
        /// <param name="column">Column. Must belong to the current entity's table.</param>
        /// <param name="relations">Relations. May be <b>null</b> if the filter doesn't use other tables.</param>
        /// <param name="filter">The search condition which restricts the rows included.</param>
        /// <returns>Maximum value in the given column. <see cref="DBNull.Value"/> if table doesn't contain any rows or 
        /// if all rows that match the criteria have a <b>null</b> value in the specified field.</returns>
        object Max(IDbColumn column, RelationBucket relations, SearchCondition filter);

        /// <summary>
        /// Retrieves the minimum value in the given column.
        /// </summary>
        /// <param name="column">Column. Must belong to the current entity's table.</param>
        /// <param name="relations">Relations. May be <b>null</b> if the filter doesn't use other tables.</param>
        /// <param name="filter">The search condition which restricts the rows included.</param>
        /// <returns>Minimum value in the given column. <see cref="DBNull.Value"/> if table doesn't contain any rows or 
        /// if all rows that match the criteria have a <b>null</b> value in the specified field.</returns>
        object Min(IDbColumn column, RelationBucket relations, SearchCondition filter);

        /// <summary>
        /// Retrieves the sum of the values in the given column.
        /// </summary>
        /// <param name="column">Column. Must be a numeric column that belongs to the current entity's table.</param>
        /// <param name="relations">Relations. May be <b>null</b> if the filter doesn't use other tables.</param>
        /// <param name="filter">The search condition which restricts the rows included.</param>
        /// <returns>The sum of the values in the given column. <see cref="DBNull.Value"/> if table doesn't contain any rows or 
        /// if all rows that match the criteria have a <b>null</b> value in the specified field.</returns>
        /// <remarks>SUM can be used with numeric columns only. Null values are ignored.</remarks>
        object Sum(IDbColumn column, RelationBucket relations, SearchCondition filter);

        /// <summary>
        /// Retrieves the average of the values in the given column.
        /// </summary>
        /// <param name="column">Column. Must be a numeric column that belongs to the current entity's table.</param>
        /// <param name="relations">Relations. May be <b>null</b> if the filter doesn't use other tables.</param>
        /// <param name="filter">The search condition which restricts the rows included.</param>
        /// <returns>The average of the values in the given column. <see cref="DBNull.Value"/> if table doesn't contain any rows or 
        /// if all rows that match the criteria have a <b>null</b> value in the specified field.</returns>
        /// <remarks>AVG can be used with numeric columns only. Null values are ignored.</remarks>
        object Avg(IDbColumn column, RelationBucket relations, SearchCondition filter);

        #endregion

        // Collection methods.
       
        #region Collection data access.

        /// <summary>
        /// Persists entities in the collection. Operation (insert, update, delete, nothing) is chosen based on the current <see cref="EntityState"/>.
        /// </summary>
        /// <param name="entitiesToSave">Entities which are to persisted.</param>
        void SaveCollection(IEnumerable entitiesToSave);

        /// <summary>
        /// Persists entities in the collection. Operation (insert, update, delete, nothing) is chosen based on the current <see cref="EntityState"/>.
        /// </summary>
        /// <param name="entitiesToSave">Entities which are to persisted.</param>
        /// <param name="fetchAutoIdentityValues">Indicates whether auto-identity values assigned to rows by DB are fetched for new/inserted rows.
        /// Setting this parameter to <b>false</b> may siginificantly improve performance.</param>
        /// <remarks><para>Preffer using this method instead of a sequence of <see cref="Save()"/> method invocations. 
        /// Future optimizers will have a better chance to speed up data access when they know in ahead what data is to be saved.</para>
        /// <para>If the <b>fetchAutoIdentityValues</b> parameter is set to <b>false</b> then this method overload will not try to retrieve
        /// IDs of the inserted records which may yield significantly better performance. If bulk saving for target DBMS is not implemented then 
        /// the logic implemented in <see cref="SaveCollection(IEnumerable)"/> method overload should be used.</para></remarks>
        void SaveCollection(IEnumerable entitiesToSave, bool fetchAutoIdentityValues);

        /// <summary>
        /// Fetched parent entities defined by the given relation from the data source and stores them into provided child entities.
        /// </summary>
        /// <param name="childEntities">Children whose FK properties define which parents are to be fetched.</param>
        /// <param name="parentsToFetch">FK. Relation to parent table from which parent records are to be fetched.</param>
        /// <returns>Parents retrieved from the data source.</returns>
        /// <remarks>Child entities with equal FK values will share the same parent object instance (same reference).</remarks>
        void FetchParentsForCollection(IEnumerable childEntities, DbRelation parentsToFetch);

        /// <summary>
        /// Fetches children which belong to provided parent entities as defined by the given relation.
        /// </summary>
        /// <param name="parentEntities">Parent entities referenced by children which are to be fetched.</param>
        /// <param name="relation">FK. Relation between parent and child tables.</param>
        /// <returns>Array of child collections retrieved from the data source. Child collections are in the
        /// same order as provided parent objects.</returns>
        /// <remarks>Child entities with equal FK values will share the same parent object instance (same reference).</remarks>
        TChildrenCollection[] FetchChildrenForCollection<TChildrenCollection>(IEnumerable parentEntities, DbRelation relation)
            where TChildrenCollection : IList, new();

        #endregion    
    }
}